Glad to have you back.
Here's a little way of the programmer advice on when to use a Lambda expression,
and when to use a named function for your key parameter when sorting.
Basically, my rule of thumb is if the lambda expression is short and simple,
so that it's pretty easy to understand what it's doing,
use the lambda expression,
and as soon as it gets too complex,
refer to a name function instead,
and give it a good name that describes the property you're trying to sort by.
For example, here's one that's just at
the outer limits of what I'd consider simple enough to put it in a lambda expression.
We have a dictionary called States.
It's got as its keys,
the names of states in the United States, Minnesota, Michigan,
and Washington, and the value associated with each state,
with each key is a list,
a list of city names.
St. Paul, Minneapolis, St.
Cloud, Stillwater for Minnesota,
Ann Arbor, Traverse City,
and so on for Michigan.
We want to sort the keys based on some property of their values.
So, we have a generic structure where we have a dictionary
called states and we're going to sort its keys.
We just asked to sort the dictionary,
but that always means we'll get to sort the keys,
and our key function is going to take
one item from that list as an input and it's going to look up some property,
in fact it's going to look up that state in the states dictionary.
But in this case, we're not just trying to get
the whole list as the value associated with Minnesota,
we're trying to get some property of that list and in this case,
we're taking square of bracket zero,
so that would get us St. Paul,
and we're passing it to the len function,
so that's going to give us eight.
For Michigan, we would take the lists that states square bracket state,
gets us the whole list of cities,
we take square bracket zero from that,
that'll get us to the city of Ann Arbor,
and we'll pass that to the len function,
so we'll get one,
two, three, four, five,
six, seven, eight, nine,
Ann Arbor has nine letters,
and similarly for Washington,
we'll get the length of Seattle,
which is seven letters.
So, when we sort this,
we should get a list of the states,
Minnesota, Michigan, and Washington,
but we should get them in the order, Washington first,
because it's first city has a shorter name.
Sure enough, we get Washington and then Minnesota, and then Michigan.
So, that's great when the property we wanted with the length of the first city name,
and as I said, I think this is sort of just at
the outer limits of what's understandable in a Lambda expression.
This got to be complicated,
it worked pretty well to understand it because states square bracket state,
and sort of chunk,
a pattern that we've seen before,
we're taking a dictionary key and we're looking up its value in the dictionary.
If you think of that as a little chunk as
that's the value of the state in the dictionary,
then we can just parse this square bracket zero to say, "Oh,
take the first element of the list and pass that to the len function."
Anything much more complicated than this,
I think would be pretty hard to read as a Lambda expression.
Well, let's think about one of those harder things.
Suppose that we wanted to take a different property.
For each state, we want to find the number of cities in its city list that begin with
the letter S. We want to sort in that order.
So, okay.
What does that property sound like?
The number of states that begin with the letter S. Number of states,
that sounds like it's going to be a count accumulation,
and only those that begin with the letter S,
that sounds like we're going to need to filter as we count.
So, once a count and filter accumulation,
it's not too hard to write it as a function,
but it would be pretty hard to write just as a lambda expression.
So, I'm going to write a function,
I'm going to call it s_cities_count,
and it's going to take as an input a city's list,
and what it's going to produce as an output is a count of
how many cities begin with a capital S. Well,
this is a count filter and accumulation,
so I'm going to say count equals zero for city in city's list,
if the first letter of city is
S then increment our counter by one.
When we finish the iteration,
ct will have the total number of cities that began with S,
so we'll return ct. Now,
how am I going to use that?
The key function is going to take one state as input,
and I wrote this city's count to do our accumulation as I was taking a city's list.
So, I can't just say key equals as cities count.
That's not going to work because the key function has to take one state as an input,
and my key function is taking a list of cities as an input.
So, this is going to be a little bit of a hybrid.
I'm going to take one state as an input,
I'm going to look it up to get the city's list.
That's sort of our canonical way of sorting a dictionary by its values,
is we look up the key state in the states dictionary,
but that's going to give me a city's list,
and I'm going to pass that to my new function.
Let's see, when you write that much code,
the chances of running without an error aren't very good,
let's see if I happened to get lucky.
Wow, I did, okay.
So, we got Michigan first and then Washington and then Minnesota.
So hopefully, if we go look at the city's list,
we'll see that Minnesota is the one that has a lot of cities beginning with S,
and sure enough it does.
Washington has St. Paul for one, St.
Cloud for two, and Stillwater for three,
so it had three.
Washington had Seattle for just one and Michigan had zero.
So, sure enough we got these in order of the number of
cities that begin with the letter S. So,
let's review what we did here again.
We made a helper function,
the name function called cities_count that did our thing,
that was a little too complicated to put into the lambda expression,
and we passed some property of our key,
the list of cities in that state,
we pass that as an input to this helper function s_cities_count.
Now, it's actually possible to not use
a lambda expression here at all and just refer to a named function,
but we would have to make our function then, take as input,
not the city's list,
but the state name.
So, I'm going to do a version of that I'm going
to call it s_cities_count_for_state,
and it's going to take a state name as its input and
it'll make the cities' list equal to lookup of the state,
in the States dictionary,
and then everything else can be the same as before.
If I do that, I can say that
my key function is
just as cities count for state.
That time I wasn't so lucky.
So, this is always instructive,
let's look at this error message,
it says syntax error EOF in multi-line statement on line 19.
Now, EOF might be a little confusing,
it's an acronym, E stands for end,
O is of, f is file, end of file.
Basically it means it got to the end of the program,
it was sort of in the middle of trying to parse something, and it's saying line 19.
So, I always like to go back and look at the first thing,
before that here's line 17 and sure enough,
I am missing a closing parenthesis,
so it was waiting around expecting there to be
another closing parenthesis and it didn't find it and so it got an error.
Let's run now, and sure enough that works exactly the same as the original.
Now, I actually prefer the original over the second one,
even though line 17 now looks very clean,
we just say key equals this function name,
but I find that the previous version and we can use
our scrubber to go back to it, let's see.
Yeah, this one, where we had key equals Lambda of state,
S cities count of states, square bracket state.
The Lambda expression is more complicated here,
but the lookup of one key in the dictionary is just a very common idiom,
when we are sorting the keys from the dictionaries.
So, that's a little advice on when to use Lambda expressions versus named functions.
My basic advice is,
if a Lambda expression is simple enough,
do it that way and when it gets too complicated to read or write,
then it's time to use a named function,
to move some things out into
another function that you can give a good name for. We'll see you next time.